if (!dojo._hasResource["dojo.parser"]) { //_hasResource checks added by build. Do not use _hasResource directly in your code.
    dojo._hasResource["dojo.parser"] = true;
    dojo.provide("dojo.parser");
    dojo.require("dojo.date.stamp");

    dojo.parser = new function() {
        // summary: The Dom/Widget parsing package

        var d = dojo;
        var dtName = d._scopeName + "Type";
        var qry = "[" + dtName + "]";

        function val2type(/*Object*/ value) {
            // summary:
            //		Returns name of type of given value.

            if (d.isString(value)) {
                return "string";
            }
            if (typeof value == "number") {
                return "number";
            }
            if (typeof value == "boolean") {
                return "boolean";
            }
            if (d.isFunction(value)) {
                return "function";
            }
            if (d.isArray(value)) {
                return "array";
            } // typeof [] == "object"
            if (value instanceof Date) {
                return "date";
            } // assume timestamp
            if (value instanceof d._Url) {
                return "url";
            }
            return "object";
        }

        function str2obj(/*String*/ value, /*String*/ type) {
            // summary:
            //		Convert given string value to given type
            switch (type) {
                case "string":
                    return value;
                case "number":
                    return value.length ? Number(value) : NaN;
                case "boolean":
                // for checked/disabled value might be "" or "checked".  interpret as true.
                    return typeof value == "boolean" ? value : !(value.toLowerCase() == "false");
                case "function":
                    if (d.isFunction(value)) {
                        // IE gives us a function, even when we say something like onClick="foo"
                        // (in which case it gives us an invalid function "function(){ foo }").
                        //  Therefore, convert to string
                        value = value.toString();
                        value = d.trim(value.substring(value.indexOf('{') + 1, value.length - 1));
                    }
                    try {
                        if (value.search(/[^\w\.]+/i) != -1) {
                            // TODO: "this" here won't work
                            value = d.parser._nameAnonFunc(new Function(value), this);
                        }
                        return d.getObject(value, false);
                    } catch(e) {
                        return new Function();
                    }
                case "array":
                    return value.split(/\s*,\s*/);
                case "date":
                    switch (value) {
                        case "": return new Date("");    // the NaN of dates
                        case "now": return new Date();    // current date
                        default: return d.date.stamp.fromISOString(value);
                    }
                case "url":
                    return d.baseUrl + value;
                default:
                    return d.fromJson(value);
            }
        }

        var instanceClasses = {
            // map from fully qualified name (like "dijit.Button") to structure like
            // { cls: dijit.Button, params: {label: "string", disabled: "boolean"} }
        };

        function getClassInfo(/*String*/ className) {
            // className:
            //		fully qualified name (like "dijit.Button")
            // returns:
            //		structure like
            //			{
            //				cls: dijit.Button,
            //				params: { label: "string", disabled: "boolean"}
            //			}

            if (!instanceClasses[className]) {
                // get pointer to widget class
                var cls = d.getObject(className);
                if (!d.isFunction(cls)) {
                    throw new Error("Could not load class '" + className +
                                    "'. Did you spell the name correctly and use a full path, like 'dijit.form.Button'?");
                }
                var proto = cls.prototype;

                // get table of parameter names & types
                var params = {};
                for (var name in proto) {
                    if (name.charAt(0) == "_") {
                        continue;
                    } 	// skip internal properties
                    var defVal = proto[name];
                    params[name] = val2type(defVal);
                }

                instanceClasses[className] = { cls: cls, params: params };
            }
            return instanceClasses[className];
        }

        this._functionFromScript = function(script) {
            var preamble = "";
            var suffix = "";
            var argsStr = script.getAttribute("args");
            if (argsStr) {
                d.forEach(argsStr.split(/\s*,\s*/), function(part, idx) {
                    preamble += "var " + part + " = arguments[" + idx + "]; ";
                });
            }
            var withStr = script.getAttribute("with");
            if (withStr && withStr.length) {
                d.forEach(withStr.split(/\s*,\s*/), function(part) {
                    preamble += "with(" + part + "){";
                    suffix += "}";
                });
            }
            return new Function(preamble + script.innerHTML + suffix);
        }

        this.instantiate = function(/* Array */nodes) {
            // summary:
            //		Takes array of nodes, and turns them into class instances and
            //		potentially calls a layout method to allow them to connect with
            //		any children
            var thelist = [];
            d.forEach(nodes, function(node) {
                if (!node) {
                    return;
                }
                var type = node.getAttribute(dtName);
                if ((!type) || (!type.length)) {
                    return;
                }
                var clsInfo = getClassInfo(type);
                var clazz = clsInfo.cls;
                var ps = clazz._noScript || clazz.prototype._noScript;

                // read parameters (ie, attributes).
                // clsInfo.params lists expected params like {"checked": "boolean", "n": "number"}
                var params = {};
                var attributes = node.attributes;
                for (var name in clsInfo.params) {
                    var item = attributes.getNamedItem(name);
                    if (!item ||
                        (!item.specified && (!dojo.isIE || name.toLowerCase() != "value"))) {
                        continue;
                    }
                    var value = item.value;
                    // Deal with IE quirks for 'class' and 'style'
                    switch (name) {
                        case "class":
                            value = node.className;
                            break;
                        case "style":
                            value = node.style && node.style.cssText; // FIXME: Opera?
                    }
                    var _type = clsInfo.params[name];
                    params[name] = str2obj(value, _type);
                }

                // Process <script type="dojo/*"> script tags
                // <script type="dojo/method" event="foo"> tags are added to params, and passed to
                // the widget on instantiation.
                // <script type="dojo/method"> tags (with no event) are executed after instantiation
                // <script type="dojo/connect" event="foo"> tags are dojo.connected after instantiation
                // note: dojo/* script tags cannot exist in self closing widgets, like <input />
                if (!ps) {
                    var connects = [],    // functions to connect after instantiation
                            calls = [];		// functions to call after instantiation

                    d.query("> script[type^='dojo/']", node).orphan().forEach(function(script) {
                        var event = script.getAttribute("event"),
                                type = script.getAttribute("type"),
                                nf = d.parser._functionFromScript(script);
                        if (event) {
                            if (type == "dojo/connect") {
                                connects.push({event: event, func: nf});
                            } else {
                                params[event] = nf;
                            }
                        } else {
                            calls.push(nf);
                        }
                    });
                }

                var markupFactory = clazz["markupFactory"];
                if (!markupFactory && clazz["prototype"]) {
                    markupFactory = clazz.prototype["markupFactory"];
                }
                // create the instance
                var instance = markupFactory ? markupFactory(params, node, clazz) :
                               new clazz(params, node);
                thelist.push(instance);

                // map it to the JS namespace if that makes sense
                var jsname = node.getAttribute("jsId");
                if (jsname) {
                    d.setObject(jsname, instance);
                }

                // process connections and startup functions
                if (!ps) {
                    d.forEach(connects, function(connect) {
                        d.connect(instance, connect.event, null, connect.func);
                    });
                    d.forEach(calls, function(func) {
                        func.call(instance);
                    });
                }
            });

            // Call startup on each top level instance if it makes sense (as for
            // widgets).  Parent widgets will recursively call startup on their
            // (non-top level) children
            d.forEach(thelist, function(instance) {
                if (instance &&
                    instance.startup &&
                    !instance._started &&
                    (!instance.getParent || !instance.getParent())
                        ) {
                    instance.startup();
                }
            });
            return thelist;
        };

        this.parse = function(/*DomNode?*/ rootNode) {
            // summary:
            //		Search specified node (or root node) recursively for class instances,
            //		and instantiate them Searches for
            //		dojoType="qualified.class.name"
            var list = d.query(qry, rootNode);
            // go build the object instances
            var instances = this.instantiate(list);
            return instances;
        };
    }();

    //Register the parser callback. It should be the first callback
    //after the a11y test.

    (function() {
        var parseRunner = function() {
            if (dojo.config["parseOnLoad"] == true) {
                dojo.parser.parse();
            }
        };

        // FIXME: need to clobber cross-dependency!!
        if (dojo.exists("dijit.wai.onload") && (dijit.wai.onload === dojo._loaders[0])) {
            dojo._loaders.splice(1, 0, parseRunner);
        } else {
            dojo._loaders.unshift(parseRunner);
        }
    })();

    //TODO: ported from 0.4.x Dojo.  Can we reduce this?
    dojo.parser._anonCtr = 0;
    dojo.parser._anon = {}; // why is this property required?
    dojo.parser._nameAnonFunc = function(/*Function*/anonFuncPtr, /*Object*/thisObj) {
        // summary:
        //		Creates a reference to anonFuncPtr in thisObj with a completely
        //		unique name. The new name is returned as a String.
        var jpn = "$joinpoint";
        var nso = (thisObj || dojo.parser._anon);
        if (dojo.isIE) {
            var cn = anonFuncPtr["__dojoNameCache"];
            if (cn && nso[cn] === anonFuncPtr) {
                return anonFuncPtr["__dojoNameCache"];
            }
        }
        var ret = "__" + dojo.parser._anonCtr++;
        while (typeof nso[ret] != "undefined") {
            ret = "__" + dojo.parser._anonCtr++;
        }
        nso[ret] = anonFuncPtr;
        return ret; // String
    }

}
